
package com.shop.cloud.mall.api.service.impl;

import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.es.utils.ElasticSearchUtil;
import com.shop.cloud.mall.api.service.*;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.entity.*;
import com.shop.cloud.mall.api.mapper.GoodsSpuMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * spu商品
 *
 * @author
 * @date 2019-08-12 16:25:10
 */
@Service
@AllArgsConstructor
public class GoodsSpuServiceImpl extends ServiceImpl<GoodsSpuMapper, GoodsSpu> implements GoodsSpuService {

	private final CouponGoodsService couponGoodsService;
	private final ElasticSearchUtil elasticSearchUtil;
	private final ActiveBorderService activeBorderService;
	private final ActiveBorderRelationService activeBorderRelationService;
	private final ActiveBackgroundService activeBackgroundService;
	private final ActiveBackgroundRelationService activeBackgroundRelationService;

	@Override
	@Cacheable(value = CacheConstants.MALL_GOODS_SPU, key = "#id")
	public GoodsSpu getById2(String id) {
		GoodsSpu goodsSpu = baseMapper.selectById2(id);
		//查询商品当前是否有活动背景图
		List<ActiveBackground> listActiveBackground = activeBackgroundService.listEnableActiveBackground();
		listActiveBackground = listActiveBackground.stream()
				.filter(item -> item.getValidEndTime().isAfter(LocalDateTime.now()) && item.getValidBeginTime().isBefore(LocalDateTime.now())).collect(Collectors.toList());
		if(listActiveBackground.size() > 0){
			ActiveBackground activeBackground = listActiveBackground.get(0);
			if(MallConstants.ACTIVE_SUIT_TYPE_1.equals(activeBackground.getSuitType())){
				goodsSpu.setActiveBackground(activeBackground);
			}
			if(MallConstants.ACTIVE_SUIT_TYPE_2.equals(activeBackground.getSuitType())){
				ActiveBackgroundRelation activeBackgroundRelation = activeBackgroundRelationService.getOne(Wrappers.<ActiveBackgroundRelation>query().lambda()
						.eq(ActiveBackgroundRelation::getRelationId, id)
						.eq(ActiveBackgroundRelation::getActiveBackgroundId, activeBackground.getId())
				);
				if(activeBackgroundRelation != null){
					goodsSpu.setActiveBackground(activeBackground);
				}
			}
			if(MallConstants.ACTIVE_SUIT_TYPE_3.equals(activeBackground.getSuitType())){
				ActiveBackgroundRelation activeBackgroundRelation = activeBackgroundRelationService.getOne(Wrappers.<ActiveBackgroundRelation>query().lambda()
						.in(ActiveBackgroundRelation::getRelationId, goodsSpu.getCategoryFirst(), goodsSpu.getCategorySecond(), goodsSpu.getCategoryThird())
						.eq(ActiveBackgroundRelation::getActiveBackgroundId, activeBackground.getId())
				);
				if(activeBackgroundRelation != null){
					goodsSpu.setActiveBackground(activeBackground);
				}
			}
			if(MallConstants.ACTIVE_SUIT_TYPE_4.equals(activeBackground.getSuitType())){
				ActiveBackgroundRelation activeBackgroundRelation = activeBackgroundRelationService.getOne(Wrappers.<ActiveBackgroundRelation>query().lambda()
						.eq(ActiveBackgroundRelation::getRelationId, goodsSpu.getShopId())
						.eq(ActiveBackgroundRelation::getActiveBackgroundId, activeBackground.getId())
				);
				if(activeBackgroundRelation != null){
					goodsSpu.setActiveBackground(activeBackground);
				}
			}
		}
		return goodsSpu;
	}

	@SneakyThrows
	@Override
	public IPage<LinkedHashMap> page2(IPage<LinkedHashMap> page, GoodsSpu goodsSpu, CouponUser couponUser) {
		//查询条件
		Query boolQuery =  boolQueryBuilder(goodsSpu, couponUser);
		//排序
		List<OrderItem> listOrderItem = page.orders();
		List<SortOptions> listSortOptions = new ArrayList<>();
		listOrderItem.forEach(orderItem -> {
			if(StrUtil.isNotBlank(orderItem.getColumn())){
				SortOptions sortOptions = new SortOptions.Builder().field(f -> {
					f.order(orderItem.isAsc() ? SortOrder.Asc : SortOrder.Desc);
					f.field(StrUtil.toCamelCase(orderItem.getColumn()));
					return f;
				}).build();
				listSortOptions.add(sortOptions);
			}
		});
		//查询请求
		int form = (int) ((page.getCurrent()-1)*page.getSize());
		int size = (int) page.getSize();
		SearchResponse<LinkedHashMap> searchResponse = elasticSearchUtil.searchPage(this.getEsSpuIndexName(), form, size, boolQuery, listSortOptions);
		List<Hit<LinkedHashMap>> hits = searchResponse.hits().hits();
		page.setTotal(searchResponse.hits().total().value());
		List<LinkedHashMap> listGoodsSpu = hits.stream()
				.map(hit -> hit.source()).collect(Collectors.toList());
		setActiveBorder(listGoodsSpu);
		page.setRecords(listGoodsSpu);
		return page;
	}

	@SneakyThrows
	@Override
	public List<LinkedHashMap> listGoodsSpuByIds(List<String> ids) {
		List<FieldValue> listIds = new ArrayList<>();
		ids.forEach(id -> {
			listIds.add(FieldValue.of(id));
		});
		TermsQueryField termsQueryField = new TermsQueryField.Builder()
				.value(listIds)
				.build();
		Query query =  new TermsQuery.Builder()
				.field("id")
				.terms(termsQueryField)
				.build()._toQuery();
		SearchResponse<LinkedHashMap> searchResponse = elasticSearchUtil.searchPage(this.getEsSpuIndexName(), 0, 9999, query,new ArrayList<>());
		List<Hit<LinkedHashMap>> hits = searchResponse.hits().hits();
		List<LinkedHashMap> listGoodsSpu = hits.stream()
				.map(hit -> hit.source()).collect(Collectors.toList());
		setActiveBorder(listGoodsSpu);
		return listGoodsSpu;
	}

	void setActiveBorder(List<LinkedHashMap> listGoodsSpu){
		//查询当前是否有活动边框
		List<ActiveBorder> listActiveBorder = activeBorderService.listEnableActiveBorder();
		listActiveBorder = listActiveBorder.stream()
				.filter(item -> item.getValidEndTime().isAfter(LocalDateTime.now()) && item.getValidBeginTime().isBefore(LocalDateTime.now())).collect(Collectors.toList());
		if(listActiveBorder.size() > 0) {
			ActiveBorder activeBorder = listActiveBorder.get(0);
			if (MallConstants.ACTIVE_SUIT_TYPE_1.equals(activeBorder.getSuitType())) {
				listGoodsSpu.stream().map(goodsSpu1 -> {
					goodsSpu1.put("activeBorder", activeBorder);
					return goodsSpu1;
				}).collect(Collectors.toList());
			}else{
				List<String> listRelationId = activeBorderRelationService.listRelationId(activeBorder.getId());
				if (MallConstants.ACTIVE_SUIT_TYPE_2.equals(activeBorder.getSuitType())) {
					listGoodsSpu.stream().map(goodsSpu1 -> {
						if(listRelationId.contains(goodsSpu1.get("id"))){
							goodsSpu1.put("activeBorder", activeBorder);
						}
						return goodsSpu1;
					}).collect(Collectors.toList());
				}
				if (MallConstants.ACTIVE_SUIT_TYPE_3.equals(activeBorder.getSuitType())) {
					listGoodsSpu.stream().map(goodsSpu1 -> {
						if(listRelationId.contains(goodsSpu1.get("categoryFirst"))
								|| listRelationId.contains(goodsSpu1.get("categorySecond"))
								|| listRelationId.contains(goodsSpu1.get("categoryThird"))
						){
							goodsSpu1.put("activeBorder", activeBorder);
						}
						return goodsSpu1;
					}).collect(Collectors.toList());
				}
				if (MallConstants.ACTIVE_SUIT_TYPE_4.equals(activeBorder.getSuitType())) {
					listGoodsSpu.stream().map(goodsSpu1 -> {
						if(listRelationId.contains(goodsSpu1.get("shopId"))){
							goodsSpu1.put("activeBorder", activeBorder);
						}
						return goodsSpu1;
					}).collect(Collectors.toList());
				}
			}
		}
	}

	@SneakyThrows
	@Override
	public boolean updateById1(GoodsSpu goodsSpu) {
		baseMapper.updateById(goodsSpu);
		//ES修改：先删后增
		elasticSearchUtil.deleteDocument(this.getEsSpuIndexName(), goodsSpu.getId());
		GoodsSpu goodsSpu1 = baseMapper.selectById(goodsSpu.getId());
		if(CommonConstants.YES.equals(goodsSpu1.getShelf())){
			elasticSearchUtil.index(this.getEsSpuIndexName(), goodsSpu.getId(), goodsSpu1);
		}
		return true;
	}

	/**
	 * es统一封装过滤条件
	 * @param goodsSpu
	 */
	Query boolQueryBuilder(GoodsSpu goodsSpu, CouponUser couponUser){
		return new Query.Builder().bool(boolQuery -> {
			//只查上架、审核通过的商品
			boolQuery.filter(q -> q.term(tq -> tq.field("shelf").value(CommonConstants.YES)));
			boolQuery.filter(q -> q.term(tq -> tq.field("verifyStatus").value(MallConstants.GOODS_STATUS_1)));
			//其他参数按条件查询
			if(StrUtil.isNotEmpty(goodsSpu.getName())){
				boolQuery.must(q -> q.multiMatch(tq -> tq.fields("name" ,"sellPoint").query(goodsSpu.getName())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getShopId())){
				boolQuery.filter(q -> q.term(tq -> tq.field("shopId").value(goodsSpu.getShopId())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getSpuCode())){
				boolQuery.filter(q -> q.term(tq -> tq.field("spuCode").value(goodsSpu.getSpuCode())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getSpecType())){
				boolQuery.filter(q -> q.term(tq -> tq.field("specType").value(goodsSpu.getSpecType())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getPointsGiveSwitch())){
				boolQuery.filter(q -> q.term(tq -> tq.field("pointsGiveSwitch").value(goodsSpu.getPointsGiveSwitch())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getPointsDeductSwitch())){
				boolQuery.filter(q -> q.term(tq -> tq.field("pointsDeductSwitch").value(goodsSpu.getPointsDeductSwitch())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getUserGradeDiscountSwitch())){
				boolQuery.filter(q -> q.term(tq -> tq.field("userGradeDiscountSwitch").value(goodsSpu.getUserGradeDiscountSwitch())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getVipDiscountSwitch())){
				boolQuery.filter(q -> q.term(tq -> tq.field("vipDiscountSwitch").value(goodsSpu.getVipDiscountSwitch())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategoryFirst())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categoryFirst").value(goodsSpu.getCategoryFirst())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategorySecond())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categorySecond").value(goodsSpu.getCategorySecond())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategoryThird())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categoryThird").value(goodsSpu.getCategoryThird())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategoryShopFirst())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categoryShopFirst").value(goodsSpu.getCategoryShopFirst())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategoryShopSecond())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categoryShopSecond").value(goodsSpu.getCategoryShopSecond())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getCategoryShopThird())){
				boolQuery.filter(q -> q.term(tq -> tq.field("categoryShopThird").value(goodsSpu.getCategoryShopThird())));
			}
			if(StrUtil.isNotEmpty(goodsSpu.getBrandId())){
				boolQuery.filter(q -> q.term(tq -> tq.field("brandId").value(goodsSpu.getBrandId())));
			}
			if(goodsSpu.getCreateTime() != null){
				LocalDate localDate = goodsSpu.getCreateTime().toLocalDate();
				boolQuery.filter(q -> q.range(tq -> tq.field("createTime")
						.gte(JsonData.of(LocalDateTime.of(localDate, LocalTime.MIN)))
						.lte(JsonData.of(LocalDateTime.of(localDate, LocalTime.MAX)))));
			}
			if(couponUser != null){//有使用券条件
				//全部商品可用，则以券店铺为条件
				boolQuery.filter(q -> q.term(tq -> tq.field("shopId").value(couponUser.getShopId())));
				if(MallConstants.COUPON_SUIT_TYPE_2.equals(couponUser.getSuitType())){//指定商品可用，则先查出所有可用SpuId，以SpuId为条件
					List<String> listSpuId = couponGoodsService.list(Wrappers.<CouponGoods>lambdaQuery().select(CouponGoods::getSpuId)
							.eq(CouponGoods::getCouponId, couponUser.getCouponId())).stream().map(CouponGoods::getSpuId).collect(Collectors.toList());
					boolQuery.filter(q -> q.terms(tq -> tq.field("id").terms(tf -> tf.value(listSpuId.stream().map(spuId -> FieldValue.of(spuId)).collect(Collectors.toList())))));
				}
			}
			return boolQuery;
		}).build();
	}

	String getEsSpuIndexName(){
		return StrUtil.format("{}_{}", "goods_spu", TenantContextHolder.getTenantId());
	}
}
